// GCC header includes to get the parse tree declarations. The order
// is important and doesn't follow any kind of logic.
//

#include <stdlib.h>
#include <gmp.h>

#include <cstdlib> // Include before GCC poison some declarations.
#include <assert.h>

extern "C"
{
#include "gcc-plugin.h"

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "tree-iterator.h"
#include "intl.h"

#include "tm.h"

#include "diagnostic.h"
#include "c-common.h"
#include "c-pragma.h"
#include "cp/cp-tree.h"
}

#include <set>
#include <string>
#include <list>

#include <strhelper.h>

#define SHOW_TREE_CODE_NAME(t)                                          \
    do {                                                                \
        if (t)                                                          \
            fprintf(stderr, " .. %s\n", tree_code_name[TREE_CODE(t)]);  \
        else                                                            \
            fprintf(stderr, " .. <nil>\n");                             \
    } while (0)

/**
 * 简化 GCC 的 AST
 */
class RefType {
protected:
    int                         _nptrs;

public:
    RefType() : _nptrs(0)
    {
    }

    virtual ~RefType()
    {
    }

    virtual void to_string(std::string& s) = 0;

    inline bool is_ptr() const { return _nptrs > 0; }

    void get_ptr_str(std::string& r)
    {
        char buf[64];

        if (_nptrs < 63) {
            memset(buf, '*', _nptrs);
            buf[_nptrs] = 0;
            r = buf;
        }
        else
            assert(0);
    }
};

class RefTypeBase : public RefType {
protected:
    const char                 *_name;

public:
    RefTypeBase() : _name(NULL)
    {
    }

    virtual ~RefTypeBase()
    {
    }
};

class FuncProto {
};

enum {
    T_VOID,

    T_UNKNOWN,

    T_INT,

    T_REAL,

    T_SU,

    T_FUNC,

    T_PTR,
};

typedef void *Type;

typedef std::list<Type>         Types;

struct Void {
    int                         type;

    Void() : type(T_VOID)
    {
    }
};

struct Unknown {
    int                         type;

    Unknown() : type(T_UNKNOWN)
    {
    }
};

struct Int {
    int                         type;

    Int() : type(T_INT)
    {
    }
};

struct Real {
    int                         type;

    Real() : type(T_REAL)
    {
    }
};

struct Func {
    int                         type;

    std::string                 name;

    int                         lineno;

    std::string                 filename;

    Type                        return_type;

    Types                       arguments;

    Func() : type(T_FUNC)
           , lineno(0)
           , return_type(NULL)
    {
    }
};

struct Ptr {
    int                         type;

    int                         nptrs;

    Type                        real_type;

    Ptr() : type(T_PTR)
          , nptrs(0)
          , real_type(NULL)
    {
    }
};

// struct or union
struct SUDecl;

typedef std::list<SUDecl *>     SUDecls;

struct SUDecl {
    std::string                 name;

    int                         lineno;

    std::string                 filename;

    SUDecls                     children;

    SUDecl                     *parent;

    Types                       fields;

    bool                        is_union;

    SUDecl() : lineno(0)
             , parent(NULL)
             , is_union(false)
    {
    }

    ~SUDecl()
    {
        SUDecls::iterator i = children.begin();
        while (i != children.end())
            delete *i++;
    }
};

struct SU {
    int                         type;

    std::string                 name;

    SUDecl                     *su_lookup;

    SU() : type(T_SU)
         , su_lookup(NULL)
    {
    }
};

struct FuncCall {
    std::string                 name;

    int                         line;

    FuncCall() : line(0)
    {
    }

    FuncCall(const char *n, int l) : name(n), line(l)
    {
    }
};

typedef std::list<FuncCall *>   FuncCalls;

typedef std::list<Func *>       Funcs;

// all function called
static FuncCalls                g_func_calls;

static SUDecl                  *g_curr_su = NULL;

static SUDecls                  g_sus;

static Funcs                    g_funcs;

int plugin_is_GPL_compatible;

inline const char *
_get_decl_name(tree decl)
{
    tree id (DECL_NAME (decl));
    const char* name (id
                      ? IDENTIFIER_POINTER (id)
                      : "<unnamed>");
    return name;
}

struct decl_comparator
{
    bool
    operator() (tree x, tree y) const
    {
        location_t xl (DECL_SOURCE_LOCATION (x));
        location_t yl (DECL_SOURCE_LOCATION (y));

        return xl < yl;
    }
};

typedef std::multiset<tree, decl_comparator> decl_set;

void
collect (tree ns, decl_set& set)
{
    tree decl;
    cp_binding_level* level (NAMESPACE_LEVEL (ns));

    // Collect declarations.
    //
    for (decl = level->names; decl != 0; decl = TREE_CHAIN (decl))
    {
        if (DECL_IS_BUILTIN (decl))
            continue;

        set.insert (decl);
    }

    // Traverse namespaces.
    //
    for(decl = level->namespaces; decl != 0; decl = TREE_CHAIN (decl))
    {
        // 加上这个，会过滤掉 std 命名空间等。。。
        // if (DECL_IS_BUILTIN (decl))
        //     continue;

        const char *nname = _get_decl_name(decl);

        fprintf(stderr, " >> namespace %s\n", nname);
        collect (decl, set);
    }
}

std::string
decl_scope (tree decl)
{
    std::string s, tmp;

    for (tree scope (CP_DECL_CONTEXT (decl));
         scope != global_namespace;
         scope = CP_DECL_CONTEXT (scope))
    {
        if (TREE_CODE (scope) == RECORD_TYPE)
            scope = TYPE_NAME (scope);

        tree id (DECL_NAME (scope));

        tmp = "::";
        tmp += (id != 0 ? IDENTIFIER_POINTER (id) : "<unnamed>");
        tmp += s;
        s.swap (tmp);
    }

    return s;
}

void
print_decl (tree decl);

enum access_spec
{
    public_, protected_, private_
};

const char* access_spec_str[] =
{
    "public", "protected", "private"
};

void
print_class (tree type)
{
    type = TYPE_MAIN_VARIANT (type);

    tree decl (TYPE_NAME (type));
    tree id (DECL_NAME (decl));
    const char* name (IDENTIFIER_POINTER (id));

    // std::cerr << "class " << decl_scope (decl) << "::" << name
    //      << " at " << DECL_SOURCE_FILE (decl)
    //      << ":" << DECL_SOURCE_LINE (decl) << endl;

    // We are done if this is an incomplete
    // class declaration.
    //
    if (!COMPLETE_TYPE_P (type))
        return;

    // Traverse base information.
    //
    tree biv (TYPE_BINFO (type));
    size_t n (biv ? BINFO_N_BASE_BINFOS (biv) : 0);

    for (size_t i (0); i < n; i++)
    {
        tree bi (BINFO_BASE_BINFO (biv, i));

        // Get access specifier.
        //
        access_spec a (public_);

        if (BINFO_BASE_ACCESSES (biv))
        {
            tree ac (BINFO_BASE_ACCESS (biv, i));

            if (ac == 0 || ac == access_public_node)
                a = public_;
            else if (ac == access_protected_node)
                a = protected_;
            else
                a = private_;
        }

        bool virt (BINFO_VIRTUAL_P (bi));
        tree b_type (TYPE_MAIN_VARIANT (BINFO_TYPE (bi)));
        tree b_decl (TYPE_NAME (b_type));
        tree b_id (DECL_NAME (b_decl));
        const char* b_name (IDENTIFIER_POINTER (b_id));

        // cerr << "\t" << access_spec_str[a] << (virt ? " virtual" : "")
        //      << " base " << decl_scope (b_decl) << "::" << b_name << endl;
    }

    // Traverse members.
    //
    decl_set set;

    for (tree d (TYPE_FIELDS (type)); d != 0; d = TREE_CHAIN (d))
    {
        switch (TREE_CODE (d))
        {
        case TYPE_DECL:
        {
            if (!DECL_SELF_REFERENCE_P (d))
                set.insert (d);
            break;
        }
        case FIELD_DECL:
        {
            if (!DECL_ARTIFICIAL (d))
                set.insert (d);
            break;
        }
        default:
        {
            set.insert (d);
            break;
        }
        }
    }

    for (tree d (TYPE_METHODS (type)); d != 0; d = TREE_CHAIN (d))
    {
        if (!DECL_ARTIFICIAL (d))
            set.insert (d);
    }

    for (decl_set::iterator i (set.begin ()), e (set.end ());
         i != e; ++i)
    {
        print_decl (*i);
    }
}

inline int
_get_real_lineno(int pos)
{
    const struct line_map *map
        = linemap_lookup (line_table, pos);

    if (map == NULL)
        return -1;

    return SOURCE_LINE (map, pos);
}

inline void
_print_ident(int depth)
{
    while (depth-- > 0)
        fprintf(stderr, "  ");
}

static void
_walk_block(tree block, int depth)
{
    while (block) {
        _print_ident(depth);
        fprintf(stderr, "%s, there is vars: %s\n",
                tree_code_name[TREE_CODE(block)],
                BLOCK_VARS(block) ? "yes" : "no");

        {
            tree vars = BLOCK_VARS(block);
            while (vars) {
                _print_ident(depth + 1);
                if (TREE_CODE(vars) == IMPORTED_DECL) {
                    tree imp = IMPORTED_DECL_ASSOCIATED_DECL(vars);
                    if (imp) {
                        fprintf(stderr, "name %s, at line %d, [%s]\n",
                                _get_decl_name(imp),
                                DECL_SOURCE_LINE(imp),
                                tree_code_name[TREE_CODE(imp)]);
                    }
                }
                else {
                    fprintf(stderr, "name %s, type %s, at line %d, [%s]\n",
                            _get_decl_name(vars),
                            tree_code_name[TREE_CODE(TREE_TYPE(vars))],
                            DECL_SOURCE_LINE(vars),
                            tree_code_name[TREE_CODE(vars)]);
                }
                vars = TREE_CHAIN(vars);
            }
        }

        _walk_block(BLOCK_SUBBLOCKS(block), depth + 1);

        block = BLOCK_CHAIN(block);
    }
}

static void
_print_tree_chain(tree t)
{
    while (t) {
        fprintf(stderr, "%s\n", tree_code_name[TREE_CODE(t)]);
        t = TREE_CHAIN(t);
    }
}

static void
_handle_typedef(tree t, std::string& res)
{
    const char *tname = _get_decl_name(t);

    tree type = TREE_TYPE(t);

    type = TYPE_MAIN_VARIANT (type);
 
    tree decl (TYPE_NAME (type));
    tree id (DECL_NAME (decl));
    const char* name (IDENTIFIER_POINTER (id));

    res += "typedef ";
    res += name;
    res += " ";
    res += tname;
}

static const char *
_get_type_name(tree type, int *nptrs)
{
    *nptrs = 0;

    if (POINTER_TYPE_P(type)) {
        do {
            if (TREE_CODE(type) == POINTER_TYPE)
                ++*nptrs;
            type = TREE_TYPE(type);
        } while (POINTER_TYPE_P(type));
    }

    type = TYPE_MAIN_VARIANT(type);

    return IDENTIFIER_POINTER(DECL_NAME(TYPE_NAME(type)));
}

static void _type_to_string(tree type, std::string& res)
{
    int nptrs;
    const char *p = _get_type_name(type, &nptrs);
    res = p;
    if (nptrs > 0) {
        res += " ";
        while (nptrs--)
            res += "*";
    }
}

static void
_handle_func_decl(tree decl, std::string& res)
{
    tree type = TREE_TYPE(decl);

    std::string  fmt;
    const char  *p;
    std::string  tmp;

    _type_to_string(TREE_TYPE(type), tmp);
    fmt += tmp;

    fmt += " ";
    fmt += _get_decl_name(decl);
    fmt += "(";

    tree arguments = TYPE_ARG_TYPES(type);
    while (arguments) {
        tree arg = TREE_VALUE(arguments);
        arguments = TREE_CHAIN(arguments);

        _type_to_string(arg, tmp);
        fmt += tmp;
        if (arguments)
            fmt += ", ";
    }
    fmt += ")";

    res = fmt;
}

static void
_handle_class_define(tree decl, std::string& res)
{
    tree type = TREE_TYPE(decl);

    if (!COMPLETE_TYPE_P (type))
        return;

    str_format(res, "class %s {\n", _get_decl_name(decl));

    // for (tree d (TYPE_FIELDS (type)); d != 0; d = TREE_CHAIN (d))
    // {
    //     switch (TREE_CODE (d))
    //     {
    //     case TYPE_DECL:
    //         if (!DECL_SELF_REFERENCE_P (d))
    //             set.insert (d);
    //         break;
    //     case FIELD_DECL:
    //         if (!DECL_ARTIFICIAL (d))
    //             set.insert (d);
    //         break;
    //     default:
    //         set.insert (d);
    //         break;
    //     }
    // }

    // for (tree d (TYPE_METHODS (type)); d != 0; d = TREE_CHAIN (d))
    // {
    //     if (!DECL_ARTIFICIAL (d))
    //         set.insert (d);
    // }

    res += "};";
}

static void
_handle_type_decl(tree decl, std::string& res)
{
    tree type = TREE_TYPE(decl);
    int  dc   = TREE_CODE(decl);

    if (type)
    {
        int tc = TREE_CODE (type);

        if (dc == TYPE_DECL && tc == RECORD_TYPE)
        {
            // If DECL_ARTIFICIAL is true this is a class
            // declaration. Otherwise this is a typedef.
            //
            if (DECL_ARTIFICIAL (decl))
            {
                _handle_class_define(decl, res);
                return;
            }
        }
    }

    res = _get_decl_name(decl);
}

void
print_decl (tree decl)
{
    // TREE_TYPE 返回值的意义
    /* In all nodes that are expressions, this is the data type of the expression.
       In POINTER_TYPE nodes, this is the type that the pointer points to.
       In ARRAY_TYPE nodes, this is the type of the elements.
       In VECTOR_TYPE nodes, this is the type of the elements.  */

    // TYPE_ARG_TYPES 的参数一定要是 FUNCTION_TYPE
    // 返回 tree_list
    // 如果最后一个是 void_type 表示这个函数不是变长参数

    tree type (TREE_TYPE (decl));
    int dc (TREE_CODE (decl));
    int tc;

    // fprintf(stderr, "  << %s: type %s, file %s, line %d >>\n",
    //         _get_decl_name(decl),
    //         tree_code_name[dc],
    //         DECL_SOURCE_FILE(decl),
    //         DECL_SOURCE_LINE(decl));

    std::string fmt;

    if (dc == TYPE_DECL && !DECL_ARTIFICIAL(decl)) {
        _handle_typedef(decl, fmt);
        fprintf(stderr, "%s\n", fmt.c_str());
        return;
    }

    switch (dc) {
    case FUNCTION_DECL:
        _handle_func_decl(decl, fmt);
        fprintf(stderr, "%s\n", fmt.c_str());
        break;

    case CONST_DECL:
        fprintf(stderr, "const decl %s\n", _get_decl_name(decl));
        break;

    case TYPE_DECL:
        _handle_type_decl(decl, fmt);
        fprintf(stderr, "%s\n", fmt.c_str());
        break;
    }

    return;

    if (type)
    {
        tc = TREE_CODE (type);

        if (dc == TYPE_DECL && tc == RECORD_TYPE)
        {
            // If DECL_ARTIFICIAL is true this is a class
            // declaration. Otherwise this is a typedef.
            //
            if (DECL_ARTIFICIAL (decl))
            {
                print_class (type);
                return;
            }
        }
    }

    if (dc == FUNCTION_DECL && 0) {
        // tree args = DECL_ARGUMENTS(decl);

        // if (args) {
        //     while (args) {
        //         tree arg_type = DECL_ARG_TYPE(args);
        //         fprintf(stderr, "argument type is %s\n", tree_code_name[TREE_CODE(arg_type)]);

        //         // the argument is a pointer
        //         if (POINTER_TYPE_P(arg_type)) {
        //             do {
        //                 fprintf(stderr, " -> %s\n", tree_code_name[TREE_CODE(arg_type)]);

        //                 arg_type = TREE_TYPE(arg_type);
        //             } while (POINTER_TYPE_P(arg_type));

        //             fprintf(stderr, " -> real type is %s\n", tree_code_name[TREE_CODE(arg_type)]);
        //         }

        //         args = TREE_CHAIN(args);
        //     }
        // }
        // else {
        //     fprintf(stderr, "no, empty arguments\n");
        // }

        tree arguments = TYPE_ARG_TYPES(type);
        fprintf(stderr, "arguments:\n");
        while (arguments) {
            tree v = TREE_VALUE(arguments);

            fprintf(stderr, " -> %s\n", tree_code_name[TREE_CODE(v)]);

            arguments = TREE_CHAIN(arguments);
        }

        // 打印返回类型
        // DECL_RESULT 在函数声明，但没有定义的时候，会返回 NULL_TREE
        // 要用以下方法得到返回的类弄
        // 一些老代码是没有返回类型的，这种老函数默认是返回 int
        if (TREE_TYPE(decl))
            fprintf(stderr, "function return type: %s\n", tree_code_name[TREE_CODE(TREE_TYPE(TREE_TYPE(decl)))]);
        else
            fprintf(stderr, "default <int> function return type\n");

        if (DECL_INITIAL(decl)) {
            // 函数的定义行号区间
            struct function *f = DECL_STRUCT_FUNCTION(decl);

            if (f) {
                // function_start_locus 的位置可能是未知的
                // 这个时候用定义的位置作为行的开始
                fprintf(stderr, "function decl between %d - %d\n",
                        (f->function_start_locus == UNKNOWN_LOCATION)
                        ? DECL_SOURCE_LINE(decl)
                        : _get_real_lineno(f->function_start_locus),
                        _get_real_lineno(f->function_end_locus));

                tree func_decl = f->decl;
                if (func_decl) {
                    fprintf(stderr, "f->decl: %s\n", tree_code_name[TREE_CODE(func_decl)]);

                    if (DECL_SAVED_TREE(func_decl))
                        fprintf(stderr, "yes\n");
                    else
                        fprintf(stderr, "no\n");
                }
            }

            tree func_body = DECL_INITIAL(decl);
            // func_body 有可能是 error_mark 结点
            if (TREE_CODE(func_body) == BLOCK)
                _walk_block(func_body, 0);
        }
        else {
            fprintf(stderr, "it's function declare\n");
        }

        if (DECL_SAVED_TREE(decl))
            fprintf(stderr, "yes\n");
        else
            fprintf(stderr, "no\n");
    }

    if (dc == TEMPLATE_DECL && 0) {
        tree ti = TI_TEMPLATE(decl);
        int  tc = TREE_CODE(ti);
        if (tc == RECORD_TYPE) {
            fprintf(stderr, "it's template class\n");

            fprintf(stderr, "template parms:\n");
            tree tparms = (DECL_TEMPLATE_PARMS(decl));
            while (tparms) {
                tree tv = TREE_VALUE(tparms);

                if (TREE_CODE(tv) == TREE_VEC) {
                    int len = TREE_VEC_LENGTH(tv);
                    fprintf(stderr, "length %d\n", len);
                    int i;
                    for (i = 0; i < len; i++) {
                        tree elt = TREE_VEC_ELT(tv, i);
                        fprintf(stderr, " -> %s, %s, %s\n",
                                tree_code_name[TREE_CODE(elt)],
                                tree_code_name[TREE_CODE(TREE_VALUE(elt))],
                                _get_decl_name(TREE_VALUE(elt)));
                    }
                }

                tparms = TREE_CHAIN(tparms);
            }

            print_class (ti);
        }
        else if (tc == FUNCTION_TYPE || tc == METHOD_TYPE) {
            fprintf(stderr, "it's template function: is method %s\n",
                    (tc == METHOD_TYPE)
                    ? "yes"
                    : "no");
            fprintf(stderr, "return type: %s\n", tree_code_name[TREE_CODE(TREE_TYPE(TI_TEMPLATE(decl)))]);
            fprintf(stderr, "arguments:\n");
            tree arguments = TYPE_ARG_TYPES(ti);
            while (arguments) {
                tree v = TREE_VALUE(arguments);
                if (v) {
                    fprintf(stderr, " -> %s\n", tree_code_name[TREE_CODE(v)]);
                    if (TREE_CODE(v) == TEMPLATE_TYPE_PARM) {
                        tree parm_decl = TEMPLATE_TYPE_DECL(v);
                        if (parm_decl) {
                            fprintf(stderr, "   -> with type %s\n", _get_decl_name(parm_decl));
                        }
                    }
                }
                arguments = TREE_CHAIN(arguments);
            }
            fprintf(stderr, "template parms:\n");
            tree tparms = (DECL_TEMPLATE_PARMS(decl));
            while (tparms) {
                tree tv = TREE_VALUE(tparms);

                if (TREE_CODE(tv) == TREE_VEC) {
                    int len = TREE_VEC_LENGTH(tv);
                    fprintf(stderr, "length %d\n", len);
                    int i;
                    for (i = 0; i < len; i++) {
                        tree elt = TREE_VEC_ELT(tv, i);
                        fprintf(stderr, " -> %s, %s, %s\n",
                                tree_code_name[TREE_CODE(elt)],
                                tree_code_name[TREE_CODE(TREE_VALUE(elt))],
                                _get_decl_name(TREE_VALUE(elt)));
                    }
                }

                tparms = TREE_CHAIN(tparms);
            }
        }
        else {
            fprintf(stderr, "unknown template type: %s\n", tree_code_name[tc]);
        }
    }
}

void
traverse (tree ns)
{
    decl_set set;
    collect (ns, set);

    for (decl_set::iterator i (set.begin ()), e (set.end ());
         i != e; ++i)
    {
        print_decl (*i);
    }
}

// static int
// dump_macro (cpp_reader *pfile, cpp_hashnode *node, void *v ATTRIBUTE_UNUSED)
// {
//   if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN))
//   {
//       fputs ("#define ", stdout);
//       fputs ((const char *) cpp_macro_definition (pfile, node), stdout);
//       putc ('\n', stdout);
//   }

//   return 1;
// }

static void
_collect_func_call(tree body, int depth)
{
    if (!body)
        return;

    int code = TREE_CODE(body);

    const char *fn = NULL;
    int call_line = 0;

    if (code == CALL_EXPR) {
        call_line = EXPR_LINENO(body);
        tree tmp = CALL_EXPR_FN(body);
        if (tmp && TREE_CODE(tmp) == ADDR_EXPR) {
            tmp = TREE_OPERAND(tmp, 0);
            if (tmp && TREE_CODE (tmp) == FUNCTION_DECL) {
                fn = _get_decl_name(tmp);

                if (fn)
                    g_func_calls.push_back(new FuncCall(fn, call_line));
            }
        }
    }

    // _print_ident(depth);

    // if (fn) {
    //     fprintf(stderr, "%s <call %s at %d>\n",
    //             tree_code_name[code], fn, call_line);
    // }
    // else {
    //     fprintf(stderr, "%s\n",
    //             tree_code_name[code]);
    // }

    if (code == STATEMENT_LIST) {
        tree_stmt_iterator it = tsi_start(body);
        while (it.ptr) {
            tree stmt = it.ptr->stmt;

            if (TREE_CODE(stmt) == BIND_EXPR)
                _collect_func_call(BIND_EXPR_BODY(stmt), depth + 1);
            else
                _collect_func_call(stmt, depth + 1);

            tsi_next(&it);
        }
    }
    else {
        if (EXPR_P(body)) {
            int oplen = TREE_OPERAND_LENGTH(body);
            int i;
            for (i = 0; i < oplen; i++) {
                tree op = TREE_OPERAND(body, i);
                _collect_func_call(op, depth + 1);
            }
        }
    }
}

extern "C" void
cb_pre_genericize (void *gcc_data, void *user_data)
{
    // If there were errors during compilation,
    // let GCC handle the exit.
    //
    if (errorcount || sorrycount)
        return;

    struct function *f = cfun;

    tree decl = f->decl;

    if (DECL_INITIAL(decl)) {
        tree body = DECL_SAVED_TREE(decl);
        _collect_func_call(body, 0);
    }
}

extern "C" void
cb_finish_parse(void *, void *)
{
    // dump the includes
    fprintf(stderr, "dump includes:\n");
    if (my_include_info) {
        my_include_info_t *curr = my_include_info;
        while (curr) {
            fprintf(stderr, " -> abs %s, header %s, line %d\n",
                    curr->dir ? curr->dir : "<NULL>",
                    curr->header, curr->lineno);
            curr = curr->next;
        }
    }

    // dump the macros
    // fprintf(stderr, "dump macros:\n");
    // if (my_macro_info) {
    //     my_macro_info_t *curr = my_macro_info;
    //     while (curr) {
    //         fprintf(stderr, "%s at %s: %d\n",
    //                 curr->def, curr->file_name, curr->line);
    //         curr = curr->next;
    //     }
    // }

    fprintf(stderr, "function called (%d):\n", g_func_calls.size());
    if (g_func_calls.size() > 0) {
        FuncCalls::iterator cur = g_func_calls.begin();
        while (cur != g_func_calls.end()) {
            FuncCall *f = *cur++;

            fprintf(stderr, " -> %s\n", f->name.c_str(), f->line);
        }
    }

    fprintf(stderr, "collecting declarations\n");
    traverse(global_namespace);
}

extern "C" void
cb_start_unit(void *gcc_data, void *user_data)
{
    (void) user_data;
    (void) gcc_data;

    my_preprecess_hook();
}

void fatal_signal(int signo)
{
    fprintf(stderr, "fatal signal got!\n");
    for (;;)
        ;
}

extern "C" int
plugin_init (plugin_name_args* info,
             plugin_gcc_version*)
{
    int r (0);

    fprintf(stderr, "processing %s...\n", main_input_filename);

    signal(SIGSEGV, fatal_signal);

    // Register callbacks.
    //
    register_callback (info->base_name,
                       PLUGIN_START_UNIT,
                       &cb_start_unit,
                       0);

    // 在每个方法 genericize 前调用
    // 这可以获得 c 和 c++ 的语言独立的 AST
    register_callback (info->base_name,
                       PLUGIN_PRE_GENERICIZE,
                       &cb_pre_genericize,
                       0);

    register_callback (info->base_name,
                       PLUGIN_FINISH_PARSE,
                       &cb_finish_parse,
                       0);

    return r;
}
